package model;

// <editor-fold defaultstate="collapsed" desc=" IMPORTS ">
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Map;
// </editor-fold>

/**
 * The Case class is responsible for storing case data. It contains enums for
 * all data fields, their types as well as case status.
 * <p>
 * @author Kevin, Tim
 * @version 2014-05-17
 */
public class Cases implements Serializable {

    private int iD;
    private User respAdministrator;
    private String caseName, crimeType, crimeLocation, crimeDescription;
    private String repFirstName, repLastName, repPhoneNumber, repEmail;
    private String registerDate, reportDate;
    private Department department;
    private Status status;
    private ArrayList<Event> events = new ArrayList<>();

    /**
     * Constructor for class Cases
     *
     * @param iD Case ID
     * @param user Responsible administrator
     * @param caseName Case name
     * @param crimeType Crime type
     * @param crimeLocation Crime location
     * @param crimeDescription Crime description
     * @param department Responsible department
     * @param repFirstName Reported by - first name
     * @param repLastName Reported by - last name
     * @param repPhoneNumber Reported by - phone number
     * @param repEmail Reported by - email
     * @param registerDate Date registered
     * @param reportDate Date reported
     * @param status Case status
     */
    public Cases(int iD, User user, String caseName, String crimeType,
            String crimeLocation, String crimeDescription, Department department,
            String repFirstName, String repLastName, String repPhoneNumber,
            String repEmail, String registerDate, String reportDate, Status status) {
        this.iD = iD;
        this.respAdministrator = user;
        this.caseName = caseName;
        this.crimeType = crimeType;
        this.crimeLocation = crimeLocation;
        this.crimeDescription = crimeDescription;
        this.department = department;
        this.repFirstName = repFirstName;
        this.repLastName = repLastName;
        this.repPhoneNumber = repPhoneNumber;
        this.repEmail = repEmail;
        this.registerDate = registerDate;
        this.reportDate = reportDate;
        this.status = status;
    }

    public Cases() {};
    
    // <editor-fold defaultstate="collapsed" desc=" GET&SET METHODS ">
      
    /**
     * Gets events
     * @return events
     */
    public ArrayList<Event> getEvents() {
        return events;
    }

    /**
     * Sets events
     * @param events
     */
    public void setEvents(ArrayList<Event> events) {
        this.events = events;
    }

    /**
     * Gets case ID
     * @return case ID
     */
    public int getiD() {
        return iD;
    }

    /**
     * Sets Case ID
     * @param iD
     */
    public void setiD(int iD) {
        this.iD = iD;
    }

    /**
     * Gets responsible administrator
     * @return responsible administrator
     */
    public User getRespAdministrator() {
        return respAdministrator;
    }

    /**
     * Sets responsible administrator
     * @param user responsible administrator
     */
    public void setRespAdministrator(User user) {
        this.respAdministrator = user;
    }

    /**
     * Gets case name
     * @return case name
     */
    public String getCaseName() {
        return caseName;
    }

    /**
     * Sets case name
     * @param caseName
     */
    public void setCaseName(String caseName) {
        this.caseName = caseName;
    }

    /**
     * Gets crime type
     * @return crime type
     */
    public String getCrimeType() {
        return crimeType;
    }

    /**
     * Sets crime type
     * @param crimeType
     */
    public void setCrimeType(String crimeType) {
        this.crimeType = crimeType;
    }

    /**
     * Gets crime location
     * @return crime location
     */
    public String getCrimeLocation() {
        return crimeLocation;
    }

    /**
     * Sets crime location
     * @param crimeLocation
     */
    public void setCrimeLocation(String crimeLocation) {
        this.crimeLocation = crimeLocation;
    }

    /**
     * Gets reporting person's first name
     * @return reporting person's first name
     */
    public String getRepFirstName() {
        return repFirstName;
    }

    /**
     * Sets reporting person's first name
     * @param repFirstName
     */
    public void setRepFirstName(String repFirstName) {
        this.repFirstName = repFirstName;
    }

    /**
     * Gets reporting person's last name
     * @return reporting person's last name
     */
    public String getRepLastName() {
        return repLastName;
    }

    /**
     * Sets reporting person's last name
     * @param repLastName
     */
    public void setRepLastName(String repLastName) {
        this.repLastName = repLastName;
    }

    /**
     * Gets reporting person's phone number
     * @return reporting person's phone number
     */
    public String getRepPhoneNumber() {
        return repPhoneNumber;
    }

    /**
     * Sets reporting person's phone number
     * @param repPhoneNumber
     */
    public void setRepPhoneNumber(String repPhoneNumber) {
        this.repPhoneNumber = repPhoneNumber;
    }

    /**
     * Get reporting person's e-mail address
     * @return reporting person's e-mail address
     */
    public String getRepEmail() {
        return repEmail;
    }

    /**
     * Sets reporting person's e-mail address
     * @param repEmail
     */
    public void setRepEmail(String repEmail) {
        this.repEmail = repEmail;
    }

    /**
     * Get date of registration
     * @return date of registration
     */
    public String getRegisterDate() {
        return registerDate;
    }

    /**
     * Set date of registration
     * @param registerDate
     */
    public void setRegisterDate(String registerDate) {
        this.registerDate = registerDate;
    }

    /**
     * Get date of report
     * @return date of report
     */
    public String getReportDate() {
        return reportDate;
    }

    /**
     * Set date of report
     * @param reportDate
     */
    public void setReportDate(String reportDate) {
        this.reportDate = reportDate;
    }

    /**
     * Get case status
     * @return case status
     */
    public Status getStatus() {
        return status;
    }

    /**
     * Set case status
     * @param status
     */
    public void setStatus(Status status) {
        this.status = status;
    }

    /**
     * Get responsible department
     * @return responsible department
     */
    public Department getDepartment() {
        return department;
    }

    /**
     * Gets crime description
     * @return crime description
     */
    public String getCrimeDescription() {
        return crimeDescription;
    }

    /**
     * setCrimeDescriptin
     * @param crimeDescription
     */
    public void setCrimeDescription(String crimeDescription) {
        this.crimeDescription = crimeDescription;
    }
    
    
// </editor-fold>
    
    /**
     * Adds an event to the case
     * @param event
     */
    public void addEvent(Event event) {
        this.events.add(event);
    }

    /**
     * Creates a Map representation of the case data.
     * <p>
     * @return an EnumMap representing case data
     */
    public EnumMap<Field, Object> toMap() {
        EnumMap<Field, Object> caseMap = new EnumMap<>(Field.class);

        /*
         for (java.lang.reflect.Field field : this.getClass().getDeclaredFields()) {
         try {
         System.out.println(field.get(this));
         } catch (IllegalArgumentException | IllegalAccessException ex) {
         Logger.getLogger(Cases.class.getName()).log(Level.SEVERE, null, ex);
         }
         }
         try {
         System.out.println(this.getClass().getDeclaredField("status").get(this));
         } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) {
         Logger.getLogger(Cases.class.getName()).log(Level.SEVERE, null, ex);
         }
         */
        caseMap.put(Field.CASE_ID, iD);
        caseMap.put(Field.CASE_NAME, caseName);
        caseMap.put(Field.CRIME_LOCATION, crimeLocation);
        caseMap.put(Field.REPORT_DATE, reportDate);
        caseMap.put(Field.CRIME_DESCRIPTION, crimeDescription);
        caseMap.put(Field.CRIME_TYPE, crimeType);
        caseMap.put(Field.RESPONSIBLE_ADMINISTRATOR, respAdministrator);
        caseMap.put(Field.RESPONSIBLE_DEPARTMENT, department);
        caseMap.put(Field.STATUS, status);
        caseMap.put(Field.REPORTING_PERSON_FIRST_NAME, repFirstName);
        caseMap.put(Field.REPORTING_PERSON_LAST_NAME, repLastName);
        caseMap.put(Field.REPORTING_PERSON_PHONE, repPhoneNumber);
        caseMap.put(Field.REPORTING_PERSON_EMAIL, repEmail);

        return caseMap;
    }

    /**
     * Sets member variables with data from a map
     * @param caseData A map containing case data
     * @return true
     */
    public boolean setData(Map caseData) {

        iD = Integer.parseInt((String) caseData.get(Field.CASE_ID));
        caseName = (String) caseData.get(Field.CASE_NAME);
        crimeLocation = (String) caseData.get(Field.CRIME_LOCATION);
        reportDate = (String) caseData.get(Field.REPORT_DATE);
        crimeDescription = (String) caseData.get(Field.CRIME_DESCRIPTION);
        crimeType = (String) caseData.get(Field.CRIME_TYPE);
        respAdministrator = (User) caseData.get(Field.RESPONSIBLE_ADMINISTRATOR);
        department = (Department) caseData.get(Field.RESPONSIBLE_DEPARTMENT);
        status = (Status) caseData.get(Field.STATUS);
        repFirstName = (String) caseData.get(Field.REPORTING_PERSON_FIRST_NAME);
        repLastName = (String) caseData.get(Field.REPORTING_PERSON_LAST_NAME);
        repPhoneNumber = (String) caseData.get(Field.REPORTING_PERSON_PHONE);
        repEmail = (String) caseData.get(Field.REPORTING_PERSON_EMAIL);

        return true;
    }

    /**
     * Enum defining all case data fields.
     */
    public enum Field {

        CASE_ID("Id"),
        CASE_NAME("Ärende"),
        REPORT_DATE("Anmälningsdatum"),
        CRIME_TYPE("Typ av brott"),
        CRIME_DESCRIPTION("Brottbeskrivning"),
        CRIME_LOCATION("Brottsplats"),
        RESPONSIBLE_DEPARTMENT("Ansvarig enhet", InputType.LIST_CHOICE, EnumSet.allOf(Department.class)),
        RESPONSIBLE_ADMINISTRATOR("Ansvarig handläggare", InputType.LIST_CHOICE),
        STATUS("Status", InputType.LIST_CHOICE, EnumSet.allOf(Cases.Status.class)),
        REPORTING_PERSON_FIRST_NAME("Förnamn"),
        REPORTING_PERSON_LAST_NAME("Efternamn"),
        REPORTING_PERSON_PHONE("Telefonnummer"),
        REPORTING_PERSON_EMAIL("E-mail");

        private final String fieldName;
        private final InputType inputType;
        private final Collection fieldChoice;

        private Field(String fieldName) {
            this(fieldName, InputType.SHORT_TEXT, null);
        }

        private Field(String fieldName, InputType inputType) {
            this(fieldName, inputType, null);
        }

        private Field(String fieldName, InputType inputType, Collection fieldChoice) {
            this.fieldName = fieldName;
            this.inputType = inputType;
            this.fieldChoice = fieldChoice;
        }

        @Override
        public String toString() {
            return fieldName;
        }

        public Collection getChoices() {
            return fieldChoice;
        }

        public InputType getInputType() {
            return inputType;
        }

        /**
         * Enum defining types of case data fields.
         */
        public enum InputType {

            SHORT_TEXT, LONG_TEXT, LIST_CHOICE
        }

        /**
         * Enum defining groups of case data fields.
         */
        public enum Group {

            CASE("Ärende", EnumSet.range(Field.CASE_ID, Field.STATUS)),
            REPORTING_PERSON("Anmälare", EnumSet.range(Field.REPORTING_PERSON_FIRST_NAME, Field.REPORTING_PERSON_EMAIL));

            private final String name;
            private final EnumSet<Field> groupSet;

            private Group(String name, EnumSet<Field> groupSet) {
                this.name = name;
                this.groupSet = groupSet;
            }

            @Override
            public String toString() {
                return name;
            }

            public EnumSet<Field> getGroup() {
                return groupSet;
            }
        }
    }

    /**
     * Enum defining case status.
     */
    public enum Status {

        REPORTED("Inrapporterad"), STARTED("Påbörjad"), DONE("Klar");

        private final String statusCode;

        private Status(String statusCode) {
            this.statusCode = statusCode;
        }

        @Override
        public String toString() {
            return this.statusCode;
        }
    }
}
